fix(mobile): drop the dead /model row and re-park the caret on draft switch - #7523
fix(mobile): drop the dead /model row and re-park the caret on draft switch#7523kirill-markin wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| !flow.submitting && | ||
| !(flow.workspaceMode === "worktree" && !flow.selectedBranchName); | ||
| // A share transfer locks the editor, so its rows must not be tappable. | ||
| const showComposerTriggerMenu = |
There was a problem hiding this comment.
🟡 Medium threads/NewTaskDraftScreen.tsx:847
When an @ search is loading or returns no matches, the trigger menu disappears without showing ComposerCommandPopover, so users receive no loading or empty-results feedback. The items.length > 0 guard makes the popover's isLoading and empty-state rendering unreachable; render it whenever a trigger is active.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/threads/NewTaskDraftScreen.tsx around line 847:
When an `@` search is loading or returns no matches, the trigger menu disappears without showing `ComposerCommandPopover`, so users receive no loading or empty-results feedback. The `items.length > 0` guard makes the popover's `isLoading` and empty-state rendering unreachable; render it whenever a trigger is active.
There was a problem hiding this comment.
Checked this against origin/main: the gate is pre-existing, not introduced here.
ThreadComposer.tsx:725 on main already reads composerTrigger && composerMenuItems.length > 0, so ComposerCommandPopover's empty-state branch — and the emptyText / "Searching files…" copy at ComposerCommandPopover.tsx:89-91,177 — was already unreachable on mobile before this PR. This patch keeps the same gate on both call sites so the two surfaces behave identically, which is what the "thread composer keeps its previous behavior exactly" constraint requires.
Relaxing it is a real improvement, but it is a deliberate UX change to both surfaces (a popover that appears on a bare @ and shows a spinner), so it belongs in its own PR rather than riding along here. Happy to send that follow-up if you want it — the one-line change is the items.length > 0 half of the condition at both call sites.
There was a problem hiding this comment.
Sorry, I'm unable to act on this request because you do not have permissions within this repository.
ApprovabilityVerdict: Would Approve Macroscope's review found this PR approvable — This is a small, localized mobile bug fix: it synchronizes caret reset on composer switches and removes a nonfunctional Not approved because:
Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
|
Status, so this does not read as abandoned — the blocking finding is answered in the review thread: #7523 (comment) Short version: the Everything else is green: Cursor Bugbot, Macroscope Effect Service Conventions, and the label checks. The Vercel marketing deploy fails with "Authorization required to deploy", which is the standard restriction on fork PRs rather than anything in this branch. I also verified this locally instead of leaning on CI: 20/20 unit tests for the extracted logic, clean |
|
Reopening: #8587 added the draft menus, but this PR also suppresses the nonfunctional /model row on drafts and resets selection synchronously when drafts change. Those details are not in the merged implementation. My initial closure missed that remaining scope. |
…switch pingdotgg#8587 landed the draft composer trigger menus. Two details it left out. `/model` bypassed the built-in capability gate, so it rendered on the new-task draft screen, where selecting it only inserts the literal text `/model `: `onSelect` has no `model` branch, and the `slash-model` trigger that follows builds no items. It is now gated on `hasThread`, so the thread composer is unchanged and the draft screen, which already carries its own model control, loses the dead row. The `ownerKey` caret reset ran in an effect, one commit too late, so switching drafts could flash the trigger popover open over a draft the user never typed a trigger into. It now adjusts during render, with the ref assigned before `setSelection` so the restarted render cannot loop. Model: Claude Opus 5, harness: Claude Code. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ce5d27c to
6c68b1c
Compare
|
@juliusmarminge — rebased onto The 775-line extraction is gone — #8587 owns that logic now, and re-landing my version of it would just be churn. What is left is one file,
Description rewritten to match. Two things in there worth your eye: with plan mode off, typing |
What this PR is now
#8587 landed the draft composer trigger menus, so the original 775-line version of this PR is obsolete. I have rebased onto
mainand cut it down to the two behaviors @juliusmarminge named when reopening it:One file,
+10 / −4, both edits inapps/mobile/src/features/threads/use-composer-command-menu.ts.1.
/modelis a dead row on the new-task draft screenallBuiltInlet/modelbypass the capability gate, so it rendered on both surfaces. Selecting it on a draft does nothing useful:onSelecthas nomodelbranch, so it inserts the literal text/model,detectComposerTriggerthen returns aslash-modeltrigger this hook builds no items for, and the menu just closes. The draft screen already has a working model control in the same toolbar ("Choose model"), so the row is redundant as well as inert.The row is now gated on
hasThread.ThreadComposerpasseshasThread: trueand is unchanged.One consequence worth naming: with plan mode off,
NewTaskDraftScreenpasses noonUpdateInteractionMode, so the built-in list is now empty. Typing/mid-line on such a draft — where provider commands are position-gated to column 0 — can produce no menu at all, whereas before it always produced the inert/modelrow. I think no menu beats a row that does nothing, but say the word if you would rather keep something there.2. The caret is re-parked a render too late
The
ownerKeyreset ran in auseEffect, which commits after the render that already computedtriggerfrom the previous draft's caret offset. Switching drafts could therefore flash the popover open over a draft the user never typed a trigger into. It now adjusts during render, so that pass never reaches the screen. The ref is assigned beforesetSelection, so the restarted render cannot loop — the same shape already used inHomeScreen.tsxandThreadNavigationSidebar.tsx.No path search was ever dispatched in that window —
useComposerPathSearchdebounces its target by 200 ms — so this is a rendering fix only.Deliberately out of scope
/modelwork on mobile. Nothing in the repo consumes theslash-modeltrigger kind thatpackages/shared/src/composerTrigger.tsproduces; onlyapps/web'sChatComposerhandles themodelcommand, by opening its own picker. So the row is inert inThreadComposertoo, not just on drafts. Pre-existing and untouched here — it needs a real mobile model picker wired into the menu. Happy to take that as its own PR.items.length > 0guard that hidesComposerCommandPopover's loading and empty states at both call sites. Relaxing it is a deliberate UX change to the most-used surface, so it stays its own PR.apps/mobilehas no hook-render harness — norenderHook, no testing-library — anduse-composer-command-menu.test.tscovers only the purecomposerSelectionAtEnd. Adding that harness, or extracting the built-in filter into a new module to assert one boolean, is more machinery than this change earns. Say the word if you would rather have it.Verification
CI on this PR is the gate; I ran no local checks. Statically:
hasThreadwas already in theitemsmemo's dependency list,ThreadComposer.tsxpasseshasThread: trueso its menu is byte-for-byte unchanged, and the clamp effect ondraftMessage.lengthis a no-op after the re-park. Happy to add an emulator pass with before/after images if you want them for this one.Model: Claude Opus 5, harness: Claude Code.